package com.ac.scum.log.task.face.log.counsumer.stages;

import com.ac.common.core.id.SnowflakeIdGenerator;
import com.ac.scum.config.bean.ServerConfigRestart;
import com.ac.scum.log.bean.Player;
import com.ac.scum.log.bean.ServerFTPLogLogin;
import com.ac.scum.log.task.face.log.counsumer.LogConsumer;
import com.ac.scum.log.task.mapper.log.ServerFTPLogLoginMapper;
import com.ac.scum.log.task.mapper.player.PlayerScoreOnlineMapper;
import com.ac.scum.log.task.mapper.server.ServerConfigRestartMapper;
import com.ac.scum.log.task.utils.map.GameMapZoneUtil;
import com.ac.scum.log.task.utils.queue.FTPQueueItem;
import com.ac.scum.player.score.bean.PlayerScoreOnline;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
@AllArgsConstructor
public class LoginLogConsumer implements LogConsumer {
    private final GameMapZoneUtil gameMapZoneUtil;
    private final PlayerScoreOnlineMapper playerScoreOnlineMapper;
    private final ServerFTPLogLoginMapper serverFTPLogLoginMapper;
    private final SnowflakeIdGenerator snowflakeIdGenerator;
    private final RedisTemplate<String, Object> redisTemplate;
    private final ServerConfigRestartMapper serverConfigRestartMapper;

    @Override
    public void consumerLog(FTPQueueItem ftpQueueItem) {
        try {
            writeAllPlayerInfoInCache(ftpQueueItem);
            String regex = "(\\d{4}\\.\\d{2}\\.\\d{2}-\\d{2}\\.\\d{2}\\.\\d{2}): '(\\d+\\.\\d+\\.\\d+\\.\\d+) (\\d+):(.*?)\\((\\d+)\\)' logged (in|out) at: X=(-?\\d+\\.\\d+) Y=(-?\\d+\\.\\d+) Z=(-?\\d+\\.\\d+)";
            String regex2 = "(\\d{4}\\.\\d{2}\\.\\d{2}-\\d{2}\\.\\d{2}\\.\\d{2}): '(\\d+\\.\\d+\\.\\d+\\.\\d+) (\\d+):(.*?)\\((\\d+)\\)' logged (in|out) at: \\?";
            String regex3 = "(\\d{4}\\.\\d{2}\\.\\d{2}-\\d{2}\\.\\d{2}\\.\\d{2}): '([\\d.]+) (\\d+):(.+?)\\((\\d+)\\)' attempted to log in as drone, but had no admin privileges";
            Pattern pattern = Pattern.compile(regex);
            Pattern pattern2 = Pattern.compile(regex2);
            Pattern pattern3 = Pattern.compile(regex3);
            List<ServerFTPLogLogin> logLogins = Lists.newArrayList();
            for (GameLogLine line : splitLine(ftpQueueItem)) {
                String lineContext = line.getLineContext();
                Matcher matcher = pattern.matcher(lineContext);
                Matcher matcher2 = pattern2.matcher(lineContext);
                Matcher matcher3 = pattern3.matcher(lineContext);
                ServerFTPLogLogin logLogin = new ServerFTPLogLogin();
                logLogin.setId(snowflakeIdGenerator.nextId());
                logLogin.setLineStart(line.getStartByte());
                logLogin.setLineEnd(line.getEndByte());
                logLogin.setFileId(ftpQueueItem.getFileId());
                logLogin.setServerId(ftpQueueItem.getServer().getId());

                if (matcher.find()) {
                    logLogin.setServerTime(parseTimestamp(matcher.group(1), ftpQueueItem));
                    logLogin.setIp(matcher.group(2));
                    logLogin.setPlayerSteamId(Long.parseLong(matcher.group(3)));
                    Player player = getOrInsertPlayerServer(logLogin.getPlayerSteamId(), logLogin.getServerId(), matcher.group(4));
                    logLogin.setPlayerId(player.getId());
                    logLogin.setAction(matcher.group(6).equals("in") ? 1 : 2);
                    logLogin.setLocation(matcher.group(7) + " " + matcher.group(8) + " " + matcher.group(9));
                    logLogin.setLocationZone(gameMapZoneUtil.getZone(Double.parseDouble(matcher.group(7)), Double.parseDouble(matcher.group(8))));
                    logLogins.add(logLogin);
                } else if (matcher2.find()) {
                    logLogin.setServerTime(parseTimestamp(matcher2.group(1), ftpQueueItem));
                    logLogin.setIp(matcher2.group(2));
                    logLogin.setPlayerSteamId(Long.parseLong(matcher2.group(3)));
                    Player player = getOrInsertPlayerServer(logLogin.getPlayerSteamId(), logLogin.getServerId(), matcher2.group(4));
                    logLogin.setPlayerId(player.getId());
                    logLogin.setAction(matcher2.group(6).equals("in") ? 1 : 2);
                    logLogin.setLocation(null);
                    logLogins.add(logLogin);
                } else if (matcher3.find()) {
                    logLogin.setServerTime(parseTimestamp(matcher2.group(1), ftpQueueItem));
                    logLogin.setIp(matcher2.group(2));
                    logLogin.setPlayerSteamId(Long.parseLong(matcher2.group(3)));
                    Player player = getOrInsertPlayerServer(logLogin.getPlayerSteamId(), logLogin.getServerId(), matcher2.group(4));
                    logLogin.setPlayerId(player.getId());
                    logLogin.setAction(3);
                    logLogin.setLocation(null);
                    logLogins.add(logLogin);
                } else {
                    commitDiscardLog(ftpQueueItem, line, "login no match");
                }
                try {
                    String redisKey = "online_time:" + logLogin.getServerId();
                    if (Boolean.TRUE.equals(redisTemplate.hasKey(redisKey))
                            || serverConfigRestartMapper.selectCount(Wrappers.lambdaQuery(ServerConfigRestart.class).eq(ServerConfigRestart::getServerId, logLogin.getServerId())) > 0) {


                        PlayerScoreOnline playerScoreOnline;
                        if (logLogin.getAction().equals(1)) {
                            playerScoreOnline = new PlayerScoreOnline();
                            playerScoreOnline.setPlayerId(logLogin.getPlayerId());
                            playerScoreOnline.setServerId(logLogin.getServerId());
                            playerScoreOnline.setLoginTime(logLogin.getServerTime());
                            playerScoreOnline.setPlayerSteamId(logLogin.getPlayerSteamId());
                            redisTemplate.opsForHash().put(redisKey, logLogin.getPlayerSteamId().toString(), playerScoreOnline);
                        } else {
                            playerScoreOnline = (PlayerScoreOnline) redisTemplate.opsForHash().get(redisKey, logLogin.getPlayerSteamId().toString());
                            if (playerScoreOnline == null) {
                                log.warn("未找到对应登录记录，跳过本条记录");
                                continue;
                            }
                            playerScoreOnline.setLogoutTime(logLogin.getServerTime());
                            Duration duration = Duration.between(playerScoreOnline.getLoginTime(), playerScoreOnline.getLogoutTime());
                            playerScoreOnline.setOnlineTime(duration.toMinutes());
                            redisTemplate.opsForHash().delete(redisKey, logLogin.getPlayerSteamId().toString());
                            playerScoreOnlineMapper.insert(playerScoreOnline);
                        }
                    }
                } catch (Exception e) {
                    log.error("统计登录日志异常", e);
                }
            }
            logLogins.forEach(serverFTPLogLoginMapper::insert);
        } catch (Exception e) {
            log.error("游戏登录日志异常", e);
        }
    }
}
